\documentclass[b5paper,9pt,twoside,openany]{article}

\input{setting}
\begin{document}
\title{使用gdb+qemu调试Linux}
\author{lenxyang}
\maketitle
\section{编译内核}
编译内核是个既简单又复杂的任务，最简单的只要执行
\begin{lstlisting}
make menuconfig
make
make install
\end{lstlisting}
编译内核就算完成了，但这种内核肯定是不能用于跟踪调试的。它包含的内容太多，、
\begin{itemize}
\item SMP架构支持
\item x86 PAE, PSE的支持
\item APIC
\item 各类driver
\end{itemize}
有太多的东西影响实现，让内核看起来非常复杂，没一部分都要认真的去读Intel的手册，而为了阅读那么由简入繁，某些硬件细节还是应该尽量去掉。
\subsection{去除不必要的功能}
\begin{itemize}
\item Processor type and features
\begin{itemize}
\item 去除Symmetric multi-processing support
\item 选择"High Memory Support (4GB)"
\item 去掉Allocate 3rd-level pagetables from highmem
\item Generic Driver Options
\end{itemize}
\item Device Drivers
\begin{itemize}
\item Multimedia support
\item Sound card support
\item HID Devices
\item Sony MemoryStick card support
\end{itemize}
\item{File systems}
\begin{itemize}
\item The Extended 4 (ext4) filesystem
\item Network File Systems
\end{itemize}
\end{itemize}

\subsection{添加完整的调试信息}
完整的调试信息能够帮助我们方便的跟踪内核的执行路径，调用栈，观察变量和内存的变化等等。这对于初学内核的人都有莫大的帮助。
\begin{itemize}
\item 选中Kernel Hacking当中的“Compile the kernel with debug info”
这一点比较容易理解，在编译完成之后会生成一个带有调试信息的vmlinux文件，此文件当中包含对应的符号信息及源代码信息。gdb可以将此文件作为符号文件加载以进行源代码级调试，这对于跟踪代码来说是必不可少的。
\item 在General setup当中去掉 “Optimize for size”并将Makefile当中的“KBUILD\_CFLAGS   += -O2”的-O2改为-O0
带有调试信息之后，用户可以进行源代码级调试。但如果启用O2调试选项，在gdb跟踪代码时，当前代码就会跳来跳去，因为编译器调整了代码的顺序；此外一些变量被优化掉了，没有办法直接查看它的值，这对跟踪代码来说都不方便。通过将O2改为-O能够禁用掉大多数优化策略，已经够用了，根本不用优化将无法通过编译，因此可以也不得不保留一部分优化。
实际上GCC提供了很多优化选项，而-O3, -Os, -O2, -O1和-O0不过是包含了这些具体优化选项的自己，如果希望了解具体的优化选项可以通过man gcc查阅。
\item 选中Kernel Hacking当中的“Compile the kernel with frame pointers”
如果不包含此选项，GCC将使用-fomit-frame-pointer进行编译，gdb将无法打出完整的backtrace信息，给跟踪代码带来不便。

\item 选中Kernel Hacking当中的“Allow gcc to uninline functions marked 'inline'”
\end{itemize}

\subsection{可能出现的错误}
\begin{itemize}
\item 去掉“Device Drivers”->“Character devices”->“ACP Modem (Mwave) support”
在改掉-O2为-O0之后，mware会编译出问题(2.6.32.60)，它是不是必要的去掉它就好。
\item arch/x86/mm/memtest.c:50: undefined reference to `\_\_udivdi3'
\item drivers/serial/serial\_core.c:759: undefined reference to `tty\_port\_users'
\item mm/slab.c:343: undefined reference to `\_\_bad\_size'
在 mm/Makefile当中增加一行
\begin{lstlisting}
CFLAGS_slab.o = -O2
\end{lstlisting}
\end{itemize}
\section{配置磁盘镜像}
\begin{lstlisting}[language=bash]
# 创建一个500M的磁盘
 bximage
 Do you want to create a floppy disk image or a hard disk image?
 Please type hd or fd. [hd] 

 What kind of image should I create?
 Please type flat, sparse or growing. [flat]

 Enter the hard disk size in megabytes, between 1 and 129023
 [10] 500

 I will create a 'flat' hard disk image with
  cyl=1015
  heads=16
  sectors per track=63
  total sectors=1023120
  total size=499.57 megabytes
\end{lstlisting}

在完成磁盘的创建以后，还需要对磁盘创建分区并格式化。Linux有一个非常方便的工具mtools可以完成功能，它提供了一组命令不需要将磁盘镜像映射成设备就可以对其操作。默认情况下linux是包含这个工具包的，可以通过命令sudo apt-get install mtools来安装。
\begin{lstlisting}[language=bash]
# mpartition -I C:
$ mpartition -cpv -t 1015 -h 16 -s 63 -b 63 C:
\end{lstlisting}

\subsection{加载磁盘镜像}
在完成磁盘的创建以后，需要对磁盘镜像以块设备的方式进行操作。
\begin{lstlisting}[language=bash]
$ sudo losetup /dev/loop0 c.img
$ ls -l /dev/loop0
brw-rw---- 1 root disk 7, 0 Feb  4 14:56 /dev/loop0 # 7, 0 是主，次设备号
# 为磁盘的分区建立设备映射
$ sudo kpartx -v -a /dev/loop0
# 将分区映射到设备 /dev/loop1上
$ sudo losetup /dev/loop1 /dev/mapper/loop0p1
# 格式化磁盘
# 注意此处应设用ext3而非ext2, 否则linux无法安装磁盘系统
$ sudo mkfs.ext3 /dev/loop1
\end{lstlisting}

\subsection{安装grub2}

\begin{lstlisting}[language=bash]
$ sudo grub-install --no-floppy \
       --root-directory=/mnt \
       --modules="fat ext2 part_msdos"  /dev/loop0
\end{lstlisting}
将c.img作为启动盘启动qemu，此时已经可以看到GRUB2的提示符号了。有一点需要注意：前面提过虚拟镜像采用ext3文件系统，而此处加载的确实ext2 modules，这不会引起什么问题。系统可以将ext3的文件系统当作ext2来加载而不会出现问题，此外GRUB2也没有ext3这个模块。
\begin{lstlisting}
qemu-system-i386 -hda c.img
\end{lstlisting}

\subsection{安装Linux}
创建文件/mnt/boot/grub/grub.cfg
\begin{lstlisting}[language=bash]

menuentry "My Linux Kernel" {
  set root='(hd0,msdos1)'
  linux /vmlinuz ro
  initrd /initrd.img
  insmod gzio
  insmod part_msdos
  insmod ext2
}
\end{lstlisting}

将生成的Linux的两个文件vmlinux和initrd.img拷贝过去。这两个文件在make install的时候会被拷贝到本地/boot目录下，从哪里copy到/mnt/下即可。

\subsection{编译busybox}
在编译之前修改编译选线
\begin{itemize}
\item 选中 "Build BusyBox as a static binary (no shared libs)"
\item 去除 "Networking Utilities"-> "inetd"
\end{itemize}
\section{创建系统目录}
\begin{lstlisting}[language=bash]
# 安装文件系统
# 将busybox生成的文件coyp /mnt下
# 创建配置文件
sudo mkdir /mnt/etc
sudo mkdir /mnt/dev/
sudo mkdir /mnt/etc/rc.d
cat > /tmp/tmp.a
#!/bin/sh
mount -t proc non /proc
mount -t sysfs non /sys
/bin/sh
mv cp /tmp/tmp.a  /mnt/etc/rc.d/rc.sysinit
sudo chmod a+x /mnt/etc/rc.d/rc.sysinit
cat > /tmp/tmp.a
# This is the first script to run when startup
::sysinit:/etc/rc.d/rc.sysinit
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a –r
sudo mv /tmp/tmp.a /mnt/etc/inittab
# 创建字符设备
sudo mkdir /mnt/dev
sudo mknod /mnt/dev/tty0 c 4 0
sudo mknod /mnt/dev/tty1 c 4 1
sudo mknod /mnt/dev/tty2 c 4 2
sudo mknod /mnt/dev/tty3 c 4 3
sudo mknod /mnt/dev/console c 5 1
sudo mknod /mnt/dev/null c 1 1
\end{lstlisting}

\subsection{运行qemu}
\begin{lstlisting}[language=bash]
qemu-system-i386  -hda c.img -m 256
\end{lstlisting}

\subsection{卸载磁盘}
在完成上面的操作以后，卸载对应的设备。
\begin{lstlisting}[language=bash]
# 关闭映射设备
$ sudo kpartx -d /dev/loop1
$ sudo losetup -d /dev/loop1
$ sudo losetup -d /dev/loop0
\end{lstlisting}

\section{调试}
\subsection{运行qemu}
\begin{lstlisting}[language=bash]
qemu-system-i386  -hda c.img -m 256 -gdb tcp::1234,nowait,nodelay,server,ipv4 -S
\end{lstlisting}
\begin{itemize}
\item -gdb tcp::1234,nowait,nodelay,server,ipv4 启动gdb调试server
\item -S qemu启动之后就会停止，指导gdb通知其继续运行
\end{itemize}

\section{编译内核}
除了前面提到的需要去掉的编译选项，还有很多是无用的（对于研究内核来说），把他们去掉可以帮助我们更加专注与核心目标。
\begin{itemize}
  \item Processor type and features
  \begin{itemize}
    \item High Resolution Timer Support
    \item Symmetric multi-processing support
    \item Paravirtualized guest support
    \item Processor family (386)
    \item PentiumPro memory ordering errata workaround
    \item /dev/cpu/microcode - microcode support
    \item /dev/cpu/*/msr - Model-specific register support
  \end{itemize}

  \item Power management and ACPI options 
  \begin{itemize}
    
  \end{itemize}

  \item Networking support
  \begin{itemize}
    \item CAN bus subsystem support
    \item IrDA (infrared) subsystem support
    \item Bluetooth subsystem support
    \item RxRPC session sockets
    \item Wireless
    \item WiMAX Wireless Broadband support
    \item RF switch subsystem support
    \item Plan 9 Resource Sharing Support (9P2000) (Experimental)
  \end{itemize}

  \item Firmware Drivers 全部去掉
  \item 
\end{itemize}
\end{document}
